#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

import os, time

from icewood import tinylog

from icewood.tca.cabinet import Cabinet


class   TestCabinet(object) :
    
    def __init__(self, data_dir) :
        self.data_dir = os.sep.join((data_dir, 'cabinet'))
        ## __init__()

    def setUp(self) :
        if os.path.exists( self.data_dir ) :
            self.removedirs( self.data_dir )
        os.makedirs( self.data_dir, 0777 )

        config = { 'bnum':10485760, 'apow':4, 'fpow':10 }
        self.cabinet = Cabinet( self.data_dir, config )
        ## setUp()

    def tearDown(self) :
        self.cabinet.close()
        ## tearDown()

    def removedirs(self, path) :
        items = os.listdir(path)
        for name in items :
            fullpath = os.sep.join((path, name))
            if os.path.isdir(fullpath) :
                self.removedirs(fullpath)
            else :
                os.remove(fullpath)

        os.rmdir(path)
        ## removedirs

    def test_101(self) :
        '''test basic read and write
        '''
        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            self.cabinet.insert(k, v)
            _v_list = self.cabinet.find(k)
            assert v == _v_list[0]

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            self.cabinet.delete( k )

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            _v_list = self.cabinet.find(k)
            assert _v_list is None
        ## test_101()

    def test_102(self) :
        '''test basic read and write
        '''
        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            self.cabinet.insertappend(k, v)
            _v_list = self.cabinet.find(k)
            assert v == _v_list[0]

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            self.cabinet.delete( k )

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            _v_list = self.cabinet.find(k)
            assert _v_list is None
        ## test_102()

    def test_103(self) :
        '''test basic read and write
        '''
        count = 0
        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-HELLO','VALUE-WORLD')) :
            self.cabinet.insertappend(k, v)
            _v_list = self.cabinet.find(k)
            count += 1
            print '  You should find %d items in list %s' % (count, _v_list)

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-HELLO','VALUE-WORLD')) :
            self.cabinet.delete( k )

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-HELLO','VALUE-WORLD')) :
            _v_list = self.cabinet.find(k)
            assert _v_list is None
        ## test_103()

    def test_002(self) :
        '''test switch function
        '''
        value_suffix = 'A' * 1024
        TIMES = 16384

        print 'Test002 : testing INSERT ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data = '-'.join((key, value_suffix))
            self.cabinet.insert( key, data )
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        INSERT %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test002 : testing INSERT done.'

        print 'Test002 : testing FIND ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data_want = '-'.join((key, value_suffix))
            data_list = self.cabinet.find( key )
            if data_list[0] != data_want :
                raise RuntimeError, 'DATA got %r, but want %r' % (data_list[0], data_want)
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        FIND %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test002 : testing FIND done.'

        print 'Test002 : testing DELETE ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            self.cabinet.delete( key )
            data_list = self.cabinet.find( key )
            if data_list :
                raise RuntimeError, 'DATA got %r, but want None' % data_list
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        print '        DELETE %d times last %.2f seconds, tps:%.2f' % (TIMES, time_last, tps)
        print 'Test002 : testing DELETE done.'
        ## test_002()

    def test_003(self) :
        '''test switch function
        '''
        value_suffix = 'A' * 1024
        TIMES = 16384

        print 'Test003 : testing INSERT-IGNORE ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data = '-'.join((key, value_suffix))
            self.cabinet.insertignore( key, data )
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        INSERT-IGNORE %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test003 : testing INSERT-IGNORE done.'

        print 'Test003 : testing FIND ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data_want = '-'.join((key, value_suffix))
            data_list = self.cabinet.find( key )
            if data_list[0] != data_want :
                raise RuntimeError, 'DATA got %r, but want %r' % (data_list[0], data_want)
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        FIND %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test003 : testing FIND done.'

        print 'Test003 : testing DELETE ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            self.cabinet.delete( key )
            data_list = self.cabinet.find( key )
            if data_list :
                raise RuntimeError, 'DATA got %r, but want None' % data_list
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        print '        DELETE %d times last %.2f seconds, tps:%.2f' % (TIMES, time_last, tps)
        print 'Test003 : testing DELETE done.'
        ## test_003()

    def test_004(self) :
        '''test switch function
        '''
        value_suffix = 'A' * 1024
        TIMES = 16384

        print 'Test004 : testing INSERT-APPEND ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data = '-'.join((key, value_suffix))
            self.cabinet.insertappend( key, data )
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        INSERT-APPEND %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test004 : testing INSERT-APPEND done.'

        print 'Test004 : testing FIND ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data_want = '-'.join((key, value_suffix))
            data_list = self.cabinet.find( key )
            if data_list[0] != data_want :
                raise RuntimeError, 'DATA got %r, but want %r' % (data_list[0], data_want)
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        FIND %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test004 : testing FIND done.'

        print 'Test004 : testing DELETE ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            self.cabinet.delete( key )
            data_list = self.cabinet.find( key )
            if data_list :
                raise RuntimeError, 'DATA got %r, but want None' % data_list
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        print '        DELETE %d times last %.2f seconds, tps:%.2f' % (TIMES, time_last, tps)
        print 'Test004 : testing DELETE done.'
        ## test_004()

    def run(self) :
        print 'running test-101 ...'
        self.setUp()
        self.test_101()
        self.tearDown()

        print 'running test-102 ...'
        self.setUp()
        self.test_102()
        self.tearDown()

        print 'running test-103 ...'
        self.setUp()
        self.test_103()
        self.tearDown()

        print 'running test-002 ...'
        self.setUp()
        self.test_002()
        self.tearDown()

        print 'running test-003 ...'
        self.setUp()
        self.test_003()
        self.tearDown()

        print 'running test-004 ...'
        self.setUp()
        self.test_004()
        self.tearDown()

        ## run()

    ## class TestCabinet

if __name__ == '__main__' :

    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option("", "--data-dir", dest="data_dir", type="string", 
                        help='path to data directory')

    parser.add_option("-l", "--logconf", dest="logconfig", type="string",
                        help='path to logging configure file')

    parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False,
                        help='show debug information')

    (options, args) = parser.parse_args()
    if not options.data_dir :
        parser.print_help( sys.stdout )
        sys.exit(0)

    if options.logconfig :
        tinylog.loadConfigure( options.logconfig )

    if options.debug :
        logger = tinylog.getLogger()
        logger.setLevel(logging.LEVEL_DEBUG)

    t = TestCabinet( options.data_dir )
    t.run()


